/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { hvigor, HvigorNode, HvigorPlugin } from '@ohos/hvigor';
import { OhosHapContext, OhosHarContext, OhosHspContext, OhosPluginId } from '@ohos/hvigor-ohos-plugin';
import { Logger, PluginError } from './common/Logger';
import HMRouterPluginConstant from './constants/CommonConstants';
import { TsAstUtil } from './utils/TsAstUtil';
import HMFileUtil from './utils/FileUtil';
import { HMRouterPluginHandle } from './HMRouterPluginHandle';
import PluginStore from './store/PluginStore'

// HMRouterPluginMgr class, used to manage HMRouterPluginHandle instances
class HMRouterPluginMgr {
  // Collection of HMRouterPluginHandle instances
  hmRouterPluginSet: Set<HMRouterPluginHandle> = new Set();

  // Constructor, start all HMRouterPluginHandle instances after the hvigor node evaluation, and delete the generated files upon hvigor build completion
  constructor() {
    hvigor.nodesEvaluated(() => {
      this.hmRouterPluginSet.forEach((pluginHandle) => {
        pluginHandle.start();
      });
    });
    hvigor.buildFinished(() => {
      Logger.info('buildFinished deleteFile exec...');
      this.hmRouterPluginSet.forEach((pluginHandle) => {
        // If saveGeneratedFile is true, skip deletion
        if (pluginHandle.config.saveGeneratedFile) {
          Logger.info(pluginHandle.config.moduleName + ' saveGeneratedFile is true, skip deleting');
          return;
        }
        this.deleteRouterMapFile(pluginHandle);
        this.deleteRawFile(pluginHandle);
        this.deleteGeneratorFile(pluginHandle);
        if (pluginHandle.config.autoObfuscation) {
          this.deleteObfuscationFile(pluginHandle);
        }
      });
      HMRouterPluginMgrInstance = null;
      TsAstUtil.clearProject();
    });
  }

  // Register HMRouterPluginHandle instance
  registerHMRouterPlugin(node: HvigorNode, pluginId: string) {
    // Get the node context
    const moduleContext = node.getContext(pluginId) as OhosHapContext | OhosHarContext | OhosHspContext;
    // If the node context is empty, throw an error
    if (!moduleContext) {
      Logger.error(PluginError.ERR_ERROR_CONFIG, node.getNodePath());
      throw new Error('moduleContext is null');
    }
    // create HMRouterPluginHandle instance
    let pluginHandle = new HMRouterPluginHandle(node, moduleContext);
    // If the plugin ID is OHOS_HAP_PLUGIN, set the module name
    let packageJson: any = HMFileUtil.readJson5(HMFileUtil.pathResolve(node.getNodePath(), 'oh-package.json5'));
    if (pluginId === OhosPluginId.OHOS_HAP_PLUGIN) {
      pluginHandle.config.moduleName = packageJson.name;
    }
    if (pluginId === OhosPluginId.OHOS_HSP_PLUGIN) {
      PluginStore.getInstance().hspModuleNames.push(packageJson.name)
    }
    // Add the HMRouterPluginHandle instance to the collection
    this.hmRouterPluginSet.add(pluginHandle);
  }

  // Delete the generated builder file
  private deleteGeneratorFile(pluginHandle: HMRouterPluginHandle) {
    // Get the builderDirPath path
    let builderDirPath = pluginHandle.config.getBuilderDir();
    // If the path exists, delete the builder directory
    if (HMFileUtil.exist(builderDirPath)) {
      HMFileUtil.rmSync(builderDirPath, {
        recursive: true
      });
      Logger.info(pluginHandle.config.modulePath + ' delete builder dir');
    }
  }

  // delete hm_router_map file
  private deleteRouterMapFile(pluginHandle: HMRouterPluginHandle) {
    let routerMapDirPath = pluginHandle.config.getRouterMapDir();
    // If the path exists, delete the hm_router_map.json file
    if (HMFileUtil.exist(routerMapDirPath)) {
      HMFileUtil.unlinkSync(routerMapDirPath);
      Logger.info(routerMapDirPath + ' delete hm_router_map.json');
    }
  }

  // Delete the routerMap directory in the rawFile
  private deleteRawFile(pluginHandle: HMRouterPluginHandle) {
    let rawFilePath = pluginHandle.config.getRawFilePath();
    if (HMFileUtil.exist(rawFilePath)) {
      HMFileUtil.unlinkSync(rawFilePath);
      Logger.info(pluginHandle.config.modulePath + ' delete rawfile hm_router_map.json');
    }
  }

  // Delete the obfuscation configuration file
  private deleteObfuscationFile(pluginHandle: HMRouterPluginHandle) {
    let obfuscationFilePath = pluginHandle.config.getObfuscationFilePath();
    if (HMFileUtil.exist(obfuscationFilePath)) {
      HMFileUtil.unlinkSync(obfuscationFilePath);
      Logger.info(pluginHandle.config.modulePath + ' delete obfuscation hmrouter-obfuscation-rules.txt');
    }
    let consumerRulesPath = pluginHandle.config.getConsumerRulesFilePath();
    if (HMFileUtil.exist(consumerRulesPath)) {
      HMFileUtil.unlinkSync(consumerRulesPath);
      Logger.info(pluginHandle.config.modulePath + ' delete hmrouter-consumer-rules.txt');
    }
  }
}

// HMRouterPluginMgr instance
let HMRouterPluginMgrInstance: HMRouterPluginMgr | null = null;

// hap plugin
export function hapPlugin(): HvigorPlugin {
  return {
    pluginId: HMRouterPluginConstant.HAP_PLUGIN_ID,
    apply(node: HvigorNode) {
      // If the HMRouterPluginMgr instance is null, create a new instance
      if (!HMRouterPluginMgrInstance) {
        HMRouterPluginMgrInstance = new HMRouterPluginMgr();
      }
      // Register the HMRouterPluginHandle instance
      HMRouterPluginMgrInstance.registerHMRouterPlugin(node, OhosPluginId.OHOS_HAP_PLUGIN);
    }
  };
}

// hsp plugin
export function hspPlugin(): HvigorPlugin {
  return {
    pluginId: HMRouterPluginConstant.HSP_PLUGIN_ID,
    apply(node: HvigorNode) {
      // If the HMRouterPluginMgr instance is null, create a new instance
      if (!HMRouterPluginMgrInstance) {
        HMRouterPluginMgrInstance = new HMRouterPluginMgr();
      }
      // register HMRouterPluginHandle instance
      HMRouterPluginMgrInstance.registerHMRouterPlugin(node, OhosPluginId.OHOS_HSP_PLUGIN);
    }
  };
}

// har plugin
export function harPlugin(): HvigorPlugin {
  return {
    pluginId: HMRouterPluginConstant.HAR_PLUGIN_ID,
    apply(node: HvigorNode) {
      // If the HMRouterPluginMgr instance is null, create a new instance
      if (!HMRouterPluginMgrInstance) {
        HMRouterPluginMgrInstance = new HMRouterPluginMgr();
      }
      // register HMRouterPluginHandle instance
      HMRouterPluginMgrInstance.registerHMRouterPlugin(node, OhosPluginId.OHOS_HAR_PLUGIN);
    }
  };
}
